package com.itheima.controller;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.itheima.config.AliyunOssConfig;
import com.itheima.pojo.FreeMark;
import com.itheima.pojo.Functions;
import freemarker.template.Configuration;
import freemarker.template.Template;
import jakarta.annotation.Resource;
import org.docx4j.Docx4J;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Random;
import java.util.UUID;

@RestController
public class FreeMarkController {
    private static final Logger log = LoggerFactory.getLogger(FreeMarkController.class);
    @Resource
    OSS ossBean;
    @Resource
    AliyunOssConfig ossConfig;
    @Value("${freeMarkerTest.image}")
    String image;
    @Value("${freeMarkerTest.ftl}")
    String ftl;


    /*
     * http://localhost:9999/freeMark
     */
    @GetMapping("/freeMark")
    public String getDept() throws IOException {
        ArrayList<FreeMark> freeMarks = new ArrayList<>();
        /*
         *数据封装
         */
        JSONObject data = getData(freeMarks);

        /**
         * 使用freemarker模板引擎
         */
        //获取指定模版
        Template template = CONFIGURATION_THREAD_LOCAL.get().getTemplate(ftl);
        try (
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                OutputStreamWriter writer = new OutputStreamWriter(byteArrayOutputStream, StandardCharsets.UTF_8)
        ) {
            //填充模版中的数据
            template.process(data, writer);
            //生成word
            byte[] bytes = byteArrayOutputStream.toByteArray();
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            WordprocessingMLPackage wmlPackage = Docx4J.load(byteArrayInputStream);
            Docx4J.save(wmlPackage, outputStream, Docx4J.FLAG_SAVE_ZIP_FILE);
            //根据流操作上传至
            ByteArrayInputStream fileInputStream = new ByteArrayInputStream(outputStream.toByteArray());
            String fileName = UUID.randomUUID() + ".docx";
            log.info("正在上传阿里云");
            ossBean.putObject(ossConfig.getBucketName(), fileName, fileInputStream);
            log.info("上传成功");
            return getA("奇瑞集团数据word", ossConfig.getUrl() + fileName);
        } catch (Exception e) {
            return "chao!";
        }
    }


    /**
     * 生成a标签的方法
     */
    private String getA(String text, String url) {
        return "<a href=\"" + url + "\">" + text + "</a>";
    }

    /**
     * 返回配置好的configuration对象
     */
    ThreadLocal<Configuration> CONFIGURATION_THREAD_LOCAL = ThreadLocal.withInitial(() -> {
        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        configuration.setDefaultEncoding("UTF-8");
        configuration.setClassLoaderForTemplateLoading(this.getClass().getClassLoader(), "/static");
        return configuration;
    });

    /**
     * 填充数据的方法
     *
     * @param freeMarks
     * @return
     */
    JSONObject getData(ArrayList<FreeMark> freeMarks) {
        // 1. 管理端功能
        FreeMark admin = new FreeMark();
        admin.setType("管理端功能:");
        Functions forAdmin1 = new Functions();
        Functions forAdmin2 = new Functions();
        Functions forAdmin3 = new Functions();
        forAdmin1.setName("订单管理:");
        forAdmin1.setDetail("主要维护用户在移动端下的订单信息，包含查询、取消、派送、完成，以及订单报表下载等功能");
        forAdmin2.setName("数据统计:");
        forAdmin2.setDetail("主要完成对餐厅的各类数据统计，如营业额、用户数量、订单等");
        forAdmin3.setName("来单提醒:");
        forAdmin3.setDetail("若有用户下单成功，Web端会有语音提示，钉钉群会有机器人报警并且钉钉和Web端都可执行接单/拒单操作。");
        admin.getFunctions().add(forAdmin1);
        admin.getFunctions().add(forAdmin2);
        admin.getFunctions().add(forAdmin3);

        // 2. 用户端功能
        FreeMark user = new FreeMark();
        user.setType("用户端功能:");
        Functions forUser1 = new Functions();
        Functions forUser2 = new Functions();
        Functions forUser3 = new Functions();
        forUser1.setName("点餐-菜单:");
        forUser1.setDetail("在点餐界面需要展示出菜品分类/套餐分类, 并根据当前选择的分类加载其中的菜品信息,供用户选择。");
        forUser2.setName("点餐-购物车:");
        forUser2.setDetail("用户选中的菜品就会加入用户的购物车, 主要包含 查询购物车、加入购物车、删除购物车、清空购物车等功能。");
        forUser3.setName("订单支付:");
        forUser3.setDetail("用户选完菜品/套餐后, 可以对购物车菜品进行下单支付,下单后系统将根据配送距离实时计算送达时间，订单预期未支付自动取消。");
        user.getFunctions().add(forUser1);
        user.getFunctions().add(forUser2);
        user.getFunctions().add(forUser3);

        // 3. 骑手端功能
        FreeMark rider = new FreeMark();
        rider.setType("骑手端功能:");
        Functions forRider1 = new Functions();
        Functions forRider2 = new Functions();
        Functions forRider3 = new Functions();
        forRider1.setName("骑手注册、登录:");
        forRider1.setDetail("手机号+验证码登录");
        forRider2.setName("骑手运单查询:");
        forRider2.setDetail("骑手查询当天或指定日期的运单情况");
        forRider3.setName("骑手接单、转单:");
        forRider3.setDetail("3.骑手确认接单或者转给其他骑手");
        rider.getFunctions().add(forRider1);
        rider.getFunctions().add(forRider2);
        rider.getFunctions().add(forRider3);

        freeMarks.add(admin);
        freeMarks.add(user);
        freeMarks.add(rider);

        JSONObject param = new JSONObject();
        param.put("freeMarks", freeMarks);
        param.put("college", "计算机与信息工程学院（大学计算机教学部）");
        param.put("grade", "2021届");
        param.put("title", "基于Springboot的外卖系统的设计与开发——小飞外卖");
        param.put("type", "自拟题目");
        param.put("specialized", "软件工程");
        param.put("teacher", "陈羽");
        param.put("position", "助教");
        param.put("peopleNum", "1人");
        param.put("lonely", "独自开发");
        //图片数据
        param.put("image", encodeImageToBase64(image));
        param.put("a", "中国饭店协会发布的《2024中国餐饮业年度报告》中指出外卖、新零售等线上营销模式已成为餐饮企业重要的盈利渠道，因此外卖行业发展情景很大。但在线外卖平台的整体呈现往龙头企业靠拢的态势，行业集中度很高。入驻在线外卖平台的商户往往会因平台的政策的变动，而改变自身的运营策略，造成一定的经济损失甚至顾客流失。为了改善这种情况，并保证本系统的生存空间，小飞外卖是一款为企业定制的外卖系统，运营策略完全由商家自主决定，自由度更高，可以更大程度地发挥企业的优势，给顾客更好的用餐体验。");
        param.put("b", "小飞外卖系统包括Web端系统管理后台、微信小程序端用户点餐系统 、微信小程序端骑手接单系统三部分。开发难点在于本系统需要对接多个第三方服务接口,比如接入高的地图计算两地距离,路线规划，接入钉钉机器人接口实现来单提醒并协同Web端完成接单拒单的功能,本系统中含有高精度的定时任务需求比如订单自动超时,需要使用中间件技术支持。本系统主要包括管理端、用户端和骑手端，具体功能如下：");
        param.put("c", "本系统是在Windows 11 系统上建立，总体技术路线采用B/S结构实现。后端采用Springboot + MyBatis + MyBatis plus框架，使用RabbitMQ消息队列作为中间件实现精准的定时任务,使用阿里云OSS实现文件上传,使用高德地图开放API实现地理逆编码以及地址间的距离计算和骑手骑行导航的路线规划。使用WebSocket技术进行长连接通信，实现前后端实时交互，用于Web端来单报警；对接钉钉机器人的三方接口，实现手机端钉钉机器人来单报警功能。数据库采用 MySQL和Redis缓存数据库。其中Redis数据库负责存放用户端数据，能够保证系统在高并发状态下能稳定运行并减轻MySql数据库的压力。前端采用H5、Vue.js、ElementUI、apache echarts(展示图表)等技术，并通过Nginx服务器部署实现均衡负载。移动端使用微信小程序构建。采用git和码云远程仓库进行系统的版本控制，并对代码进行远程上传和管理。");
        param.put("d", "餐饮企业通过Web端系统管理后台可以更加高效地管理餐厅的各项业务，如菜品管理、订单处理、员工调度等。这不仅减少了人工操作的时间和错误率，还能够让企业人员更快、更精准地获取到餐厅的各项数据数据比如日营业额，周营销曲线等，以便及辅助管理人员及时调整营销策略，做出更妥当的运营策略。");
        param.put("e", "用户无需下载APP可以直接通过微信小程序进入系统进行浏览菜单、选择菜品和下单支付等操作，并提供送货上门服务，无需外出寻找餐厅。用户还可以通过小程序实时跟踪自己的订单状态，增加了服务的透明度。因此本系统的用户端可以为用户提供极大的便利和更好的用餐体验，不仅能增加餐厅的回头客数量，也能通过顾客的宣传提高餐厅的知名度创造更多的营收。");
        param.put("f", "对于骑手而言，专门的小程序端提供了从接单到配送到导航的一系列功能支持，使得外卖配送过程更加流畅和高效。能够吸引更多的骑手入住本系统，这样不仅能创造更多的就业岗位，还能减少订单接单时的等待时间，间接提高了用户的点餐体验，从而提高本系统在市场上的竞争力。");
        return param;
    }

    /**
     * 将url图片转化为Base64编码
     *
     * @param imageUrl
     * @return
     */
    public static String encodeImageToBase64(String imageUrl) {
        try (InputStream inputStream = new URL(imageUrl).openStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            byte[] imageBytes = outputStream.toByteArray();
            System.err.println(Base64.getEncoder().encodeToString(imageBytes));
            return Base64.getEncoder().encodeToString(imageBytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


}
